
//
//  YKAudioPlayer.m
//  YK_BaseTools
//
//  Created by edward on 2018/11/27.
//  

#import "YKAudioPlayer.h"
#import <AVFoundation/AVFoundation.h>

@interface YKAudioPlayer()
{
    BOOL isObserving;
}
/** 定时器启动开始 经过的时间 */
@property (nonatomic, assign) NSInteger currentDuration;

/** 记录播放状态 */
@property (nonatomic, strong) NSMutableDictionary *playStatusDic;

/** 记录播放的url */
@property (nonatomic, strong) NSMutableDictionary *audioUrlDic;

/** 正在播放的id */
@property (nonatomic, copy) NSString *playingId;

@property (nonatomic, strong) AVPlayer *audioPlay;

@property (nonatomic, assign) CGFloat progress;
@property (nonatomic, copy) NSString *restTime;
@property (nonatomic, copy) NSString *total;

@property (nonatomic, strong) id  timeObserve;
//TODO:改代理
//@property (nonatomic, strong) RACDisposable *disposeable;
//@property (nonatomic, strong) RACDisposable *routerDisopseable;
//@property (nonatomic, strong) RACSubject *statusChangeSubject;

/** 是否停止当暂停用 */
@property (nonatomic, assign) BOOL pauseToStop;

@end

@implementation YKAudioPlayer

static YKAudioPlayer *_instance;

+ (id)allocWithZone:(struct _NSZone *)zone
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _instance = [super allocWithZone:zone];
    });

    return _instance;
}

+ (instancetype)sharedInstance
{
    if (_instance == nil) {
        _instance = [[YKAudioPlayer alloc] init];
    }

    return _instance;
}

- (instancetype)init
{
    if (self = [super init]) {
//        @weakify(self);
        __weak typeof(self) weakSelf = self;
        [[NSNotificationCenter defaultCenter] addObserverForName:AVAudioSessionInterruptionNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * _Nonnull note) {
//            @strongify(self);
            __strong typeof(self) strongSelf = weakSelf;
            AVAudioSessionInterruptionType type = [note.userInfo[AVAudioSessionInterruptionTypeKey] intValue];
            if (AVAudioSessionInterruptionTypeBegan == type) {
                [strongSelf endPlay];
            }
        }];
    }
    return self;
}

- (void)registerPlayStatusWithId:(NSString *)Id audioUrl:(NSString *)audio
{
    if (!Id || !audio) return;
    if ( [audio hasPrefix:@"file:///"] ) {
        // 本地url
        audio = [audio stringByReplacingOccurrencesOfString:@"file:///" withString:@""];
    }
//    if (audio.lastPathComponent.pathExtension.length == 0) {
//        audio = [audio stringByAppendingPathExtension:@"aac"];
//    }

    [self.playStatusDic setObject:@(YKCellVoicePlayStatusNeverPlaying) forKey:Id];
    [self.audioUrlDic setObject:audio forKey:Id];
}

- (void)markPlayingId:(NSString *)Id pauseToStop:(BOOL)pauseToStop
{
    self.pauseToStop = pauseToStop;
    if(self.playingId && ![self.playingId isEqualToString:Id]) {
        // 若当前正在播放的id不是传入的id,先将当前的id播放状态置为停止
        self.playStatusDic[self.playingId] = @(YKCellVoicePlayStatusFinish); // 播放停止
        // 重置进度
        [self endPlay];
    } else if (self.playingId && [self.playingId isEqualToString:Id]) {
        // 传入的id就是当前播放的id
        if ( [self.playStatusDic[Id] integerValue] == YKCellVoicePlayStatusPause){
            // 当前状态是停止的就改为继续播放
            self.playStatusDic[Id] = @(YKCellVoicePlayStatusPlaying);
            [self.audioPlay play];
        }else if ([self.playStatusDic[Id] integerValue] == YKCellVoicePlayStatusPlaying){
            if (pauseToStop) {
                // 当前状态是播放的就改为停止
                self.playStatusDic[Id] = @(YKCellVoicePlayStatusFinish);
                self.progress = 0;
                [self endPlay];
            } else {
                // 当前状态是播放的就改为暂停
                self.playStatusDic[Id] = @(YKCellVoicePlayStatusPause);
                [self.audioPlay pause];
            }
        }else{
            // 其他状态的就改为播放结束
            self.playStatusDic[Id] = @(YKCellVoicePlayStatusFinish);
            self.playingId = nil;
            
        }
        //TODO:写成代理
//        [self.statusChangeSubject sendNext:RACTuplePack(self.playStatusDic[Id],Id)];
        
        return;
    }
    
    __weak typeof(self) weakSelf = self;
    void(^playAudio)(void) = ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;
        strongSelf.playStatusDic[Id] = @(YKCellVoicePlayStatusPlaying); // 播放开始
        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        CGFloat currentVol = audioSession.outputVolume;
        if (currentVol < 0.3) {
            if (strongSelf.hintBlock) {
                strongSelf.hintBlock(@"音量过低，建议调高音量");
            }
        }
        // 是否外接设备
        BOOL isEarphone = [strongSelf isHeadsetPluggedIn];
        if (isEarphone) {
            if(strongSelf.hintBlock) {
                strongSelf.hintBlock(@"正通过耳机播放中");
            }
        }
        strongSelf.playingId = Id;
        [strongSelf playAudioWithId:strongSelf.playingId];
        //TODO:改成代理
//        [strongSelf.statusChangeSubject sendNext:RACTuplePack(strongSelf.playStatusDic[Id],Id)];
    };
    
    // 在准备开始播放音频的时候,检查音频冲突，并解决这些冲突
    BOOL needHandle = NO;
    if ([self.conflictDelegate respondsToSelector:@selector(audio:handleConflictIfNeed:)]) {
        needHandle = [self.conflictDelegate audio:self handleConflictIfNeed:^(BOOL complete) {
            if (complete) {
                playAudio();
            }
        }];
    }
    
    // 如果要处理的话就先不播放，hold住
    if (needHandle) {
        return;
    }
    
    // 直接开始播放
    playAudio();
}

- (void)markPlayingId:(NSString *)Id
{
    [self markPlayingId:Id pauseToStop:NO];
}

- (void)markStopPlayingId:(NSString *)Id
{
    if (Id && [self.playStatusDic.allKeys containsObject:Id]) {
        self.playStatusDic[Id] = @(YKCellVoicePlayStatusFinish);
    }
    if (self.playingId) {
        self.playStatusDic[self.playingId] = @(YKCellVoicePlayStatusFinish);
        self.playingId = nil;
    }
    [self endPlay];
}

- (YKCellVoicePlayStatus)playStatusWithId:(NSString *)Id
{
    return [self.playStatusDic[Id] integerValue];
}

/*
 * 播放完毕
 */
- (void)endPlay {
    if (self.audioPlay == nil) return;
    [self.audioPlay pause];
    if (self.playingId && [self.playStatusDic.allKeys containsObject:self.playingId]) {
        self.playStatusDic[self.playingId] = @(YKCellVoicePlayStatusFinish);
    }
    self.playingId = @"";
    //移除监控
    [self removeObserver];
    
    //重置进度
    self.progress = 0.f;
    
    self.audioPlay = nil;
}

- (void)pausePlay
{
    // 当前状态是播放的就改为暂停
    if(self.audioPlay &&
       self.playingId &&
       self.playingId.length > 0 &&
       [self.playStatusDic.allKeys containsObject:self.playingId] &&
       [self.playStatusDic[self.playingId] integerValue] == YKCellVoicePlayStatusPlaying) {
        self.playStatusDic[self.playingId] = @(YKCellVoicePlayStatusPause);
        [self.audioPlay pause];
    }
}

- (void)resumePlay
{
    // 当前状态是播放的就改为暂停
    if(self.audioPlay &&
       self.playingId &&
       self.playingId.length > 0 &&
       [self.playStatusDic.allKeys containsObject:self.playingId] &&
       [self.playStatusDic[self.playingId] integerValue] == YKCellVoicePlayStatusPause) {
        self.playStatusDic[self.playingId] = @(YKCellVoicePlayStatusPlaying);
        [self.audioPlay play];
    }
}

- (void)playAudioWithId:(NSString *)Id {
    NSString *soundPath = self.audioUrlDic[Id];
    NSURL *soundUrl;
    if (!soundPath) return;
    if ([soundPath hasPrefix:@"http://"] || [soundPath hasPrefix:@"https://"]) {
        soundUrl = [NSURL URLWithString:soundPath];
    } else {
        soundUrl = [NSURL fileURLWithPath:soundPath];
    }
    @try {
        if (self.audioPlay) {
            [self removeObserver];
        }
        
        AVAudioSession *session =[AVAudioSession sharedInstance];
        [session setCategory:AVAudioSessionCategoryPlayback error:nil];
        
        AVPlayerItem *songItem = [[AVPlayerItem alloc] initWithURL:soundUrl];
        self.audioPlay = [[AVPlayer alloc]initWithPlayerItem:songItem];
        float total = CMTimeGetSeconds(songItem.duration);
        self.total = @(total).stringValue;
        self.restTime = @"0";
        [self.audioPlay replaceCurrentItemWithPlayerItem:songItem];
        [self.audioPlay addObserver:self forKeyPath:@"status" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:nil];
        isObserving = YES;
        __weak typeof(self) weakSelf = self;
         self.timeObserve = [self.audioPlay addPeriodicTimeObserverForInterval:CMTimeMake(1, 60) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
             __strong typeof(weakSelf) strongSelf = weakSelf;
            float current = CMTimeGetSeconds(time);
            float total = CMTimeGetSeconds(songItem.duration);
            //        SuLog(@"%f, %f",current, total);
             CGFloat progress = CMTimeGetSeconds(strongSelf.audioPlay.currentItem.currentTime) / CMTimeGetSeconds(strongSelf.audioPlay.currentItem.duration);
             //在这里截取播放进度并处理
            if (current) {
                strongSelf.progress = progress;
    //            current / total;
                NSString *playTime = [NSString stringWithFormat:@"%.f",current];
                strongSelf.restTime = @(total - current).stringValue;
                strongSelf.total = @(total).stringValue;
//                LMLog(@"%@----%@",playTime,self.restTime);
            }
        }];
        
        //TODO:改成代理
//        [self.disposeable dispose];
//        self.disposeable = [[[[NSNotificationCenter defaultCenter] rac_addObserverForName:AVPlayerItemDidPlayToEndTimeNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(id  _Nullable x) {
//            @strongify(self);
//            // 其他状态的就改为播放结束
//            self.playStatusDic[Id] = @(LMCellVoicePlayStatusFinish);
//            self.progress = 0;
//            self.playingId = nil;
//            [self.statusChangeSubject sendNext:RACTuplePack(self.playStatusDic[Id],Id)];
//        }];
//        [self.routerDisopseable dispose];
//        self.routerDisopseable = [[[[NSNotificationCenter defaultCenter] rac_addObserverForName:AVAudioSessionRouteChangeNotification object:nil] takeUntil:self.rac_willDeallocSignal] subscribeNext:^(NSNotification * _Nullable notification) {
//            @strongify(self);
//            NSDictionary *interuptionDict = notification.userInfo;
//            NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
//            switch (routeChangeReason) {
//                case AVAudioSessionRouteChangeReasonNewDeviceAvailable:
//                    if (self.playingId) {
//                        if ([self playStatusWithId:self.playingId] == LMCellVoicePlayStatusPause) {
//                            [self markPlayingId:self.playingId pauseToStop:self.pauseToStop];
//                        }
//                    }
//                    break;
//                case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
//                    if (self.playingId) {
//                        if ([self playStatusWithId:self.playingId] == LMCellVoicePlayStatusPlaying) {
//                            [self markPlayingId:self.playingId pauseToStop:self.pauseToStop];
//                        }
//                    }
//                    break;
//                case AVAudioSessionRouteChangeReasonCategoryChange:
//                    // called at start - also when other audio wants to play
//                    break;
//            }
//        }];
    } @catch (NSException *exception) {
        NSLog(@"音频播放发生错误：%@",exception);
    }
}


//MARK: 滑动到指定的时间
- (void)seekToTime:(CMTime)time Id:(NSString *)Id
{
    if(self.playingId && self.playingId != Id) {
        // 播放对应的音频
        [self markPlayingId:Id];
    }
    
    // 当前状态是播放的就改为暂停
    self.playStatusDic[Id] = @(YKCellVoicePlayStatusPause);
    [self.audioPlay pause];
    
    __weak typeof(self) weakSelf = self;
    if (self.audioPlay.status == AVPlayerStatusReadyToPlay) {
        [self.audioPlay seekToTime:time toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero completionHandler:^(BOOL finished) {
            __strong typeof(weakSelf) strongSelf = weakSelf;
            strongSelf.playingId = Id;
            [strongSelf.audioPlay play];
            strongSelf.playStatusDic[Id] = @(YKCellVoicePlayStatusPlaying);
        }];
    }
}

// MARK:KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItemStatus status = [change[@"new"] integerValue];
        NSLog(@"现在的播放器状态是 %zd",status);
        switch (status) {
            case AVPlayerItemStatusReadyToPlay:  // 1
            {
                // 开始播放
                [self.audioPlay play];
            }
                break;
            case AVPlayerItemStatusFailed: // 2
            {
                NSLog(@"加载失败");
                [[NSNotificationCenter defaultCenter] postNotificationName:kPlayErrorNotificationName object:nil userInfo:@{@"msg":@"加载失败"}];
            }
                break;
            case AVPlayerItemStatusUnknown: // 0
            {
                NSLog(@"未知资源");
                [[NSNotificationCenter defaultCenter] postNotificationName:kPlayErrorNotificationName object:nil userInfo:@{@"msg":@"资源不存在"}];
            }
                break;
            default:
                break;
        }
    }
}

// 移除监听
- (void)removeObserver {
    if (self.timeObserve) {
        [self.audioPlay removeTimeObserver:self.timeObserve];
        self.timeObserve = nil;
    }
    
    if (isObserving) {
        [self.audioPlay removeObserver:self forKeyPath:@"status"];
        isObserving = NO;
    }
    [self.audioPlay replaceCurrentItemWithPlayerItem:nil];
}

- (BOOL)isHeadsetPluggedIn {
    AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];
    for (AVAudioSessionPortDescription* desc in [route outputs]) {
        if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones] ||
            [[desc portType] isEqualToString:AVAudioSessionPortBluetoothLE] ||
            [[desc portType] isEqualToString:AVAudioSessionPortBluetoothA2DP] ||
            [[desc portType] isEqualToString:AVAudioSessionPortBluetoothHFP])
            return YES;
    }
    return NO;
}

- (NSMutableDictionary *)playStatusDic
{
    if (!_playStatusDic) {
        _playStatusDic = [NSMutableDictionary dictionary];
    }
    return _playStatusDic;
}

- (NSMutableDictionary *)audioUrlDic
{
    if (!_audioUrlDic) {
        _audioUrlDic = [NSMutableDictionary dictionary];
    }
    return _audioUrlDic;
}

//TODO:改成代理
//- (RACSubject<RACTuple *> *)statusChangeSubject
//{
//    if (!_statusChangeSubject){
//        _statusChangeSubject = [RACSubject subject];
//    }
//    return _statusChangeSubject;
//}

@end
